package DBIx::Class::Component::DataValidator::DBMS;

use strict;
use Class::C3;

use base qw/
    DBIx::Class
/;

our $VERSION = '0.05';

=head1 NAME

DBIx::Class::Component::DataValidator::DBMS - Base class for DBMS aware data validation

=head1 DESCRIPTION

Each DBMS has its own datatypes with a unique definition. Also, there is a big
amount of shared datatypes such as simple integer values. Thus, this class
provides validation for all those shared datatypes and also acts as base class
for all DBSM specific (MySQL, SQLLite and so on) validation classes.

=cut

__PACKAGE__->mk_classdata( $_ ) for qw/
    _validate_data_type
/;

=head1 METHODS

=head2 add_datatype_validators

to be called from the DBMS classes to add new types for validation

=cut

sub add_datatype_validators {
    my ( $self, $ref ) = @_;
    $self->_validate_data_type( {} )
        unless $self->_validate_data_type;
    $self->_validate_data_type->{ $_ } = $ref->{ $_ } foreach keys %$ref;;
}


=head2 load_datatype_validator

to be called from the add_columns method in DBIx::Class::Component::DataValidator for getting
the specific validation for a column data type

=cut

sub load_datatype_validator {
    my ( $self, $data_type, $col_ref, $col ) = @_;
    if ( my $validator_ref = $self->_validate_data_type->{ $data_type } ) {
        if ( !ref( $validator_ref ) && $validator_ref =~ /^map:(.+?)$/ ) {
            $validator_ref = $self->_validate_data_type->{ $1 };
        }
        if ( ref( $validator_ref ) =~ /^CODE/ ) {
            my $orig_sub = $validator_ref;
            $validator_ref = sub {
                $orig_sub->( shift, $col_ref, shift );
            };
        }
        return {
            %$col_ref,
            validation => {
                constraint => $validator_ref
            }
        } if $validator_ref;
    }
    
    return $col_ref;
}


=head2 can_datatype_validator

returns bool wheter any validator is registered for this datatype

=cut

sub can_datatype_validator {
    my ( $self, $data_type, $col_ref ) = @_;
    return defined $self->_validate_data_type->{ $data_type };
}





=head1 DEFAULT DATATYPE VALIDATORS

=head2 integer | int

for all integer values. Checks wheter only numbers are given

=head2 decimal | float | double | real

for all decimal values. Checks wheter only decimal or interger numbers are given

=head2 varchar | char | character

if a maximum size for the column is given -> checks wheter the given string isnt to long


=cut

__PACKAGE__->add_datatype_validators( {
    
    # integer, numeric types
    int     => sub {
        my ( $dv, $col_ref, $col ) = @_;
        return 0 if ! defined $col && ! $col_ref->{ is_nullable };
        return $col =~ /^\d+$/;
    },
    integer => 'map:int',
    decimal => sub {
        my ( $dv, $col_ref, $col ) = @_;
        return 0 if ! defined $col && ! $col_ref->{ is_nullable };
        return $col =~ /^\d+(?:\.\d+)?$/;
    },
    float   => 'map:decimal',
    double  => 'map:decimal',
    real    => 'map:decimal',
    
    # charcacter types
    varchar => sub {
        my ( $dv, $col_ref, $col ) = @_;
        return 0 if ! defined $col && ! $col_ref->{ is_nullable };
        if ( ( my $size = $col_ref->{ size } ) > 0 ) {
            return length( $col ) <= $col_ref->{ size };
        }
        return 1;
    },
    char      => 'map:varchar',
    character => 'map:varchar',
} );



1;
